﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Data;
using System.Windows.Forms;

namespace CashCommon
{
    public class Sequence
    {
        // Public
        /// <summary>
        /// Открытие набора данных
        /// </summary>
        public void Open()
        {
            SqlGate.Open(this);
            if (this._dgv != null)
            {
                _dgv.Columns.Clear();
                _dgv.DataSource = this.DT;

                // Установка наименования столбцов
                foreach (DataColumn dc in DT.Columns)
                    _dgv.Columns[dc.ColumnName].HeaderText = Fields.Where(t => t[0] == dc.Caption.ToUpper()).ElementAt(0)[1].ToString();

            }
        }
        /// <summary>
        /// Получение следующей страницы набора данных
        /// </summary>
        public void Next()
        {
            SqlGate.Next(this);
        }
        /// <summary>
        /// Получение предыдущей страницы набора данных
        /// </summary>
        public void Prior()
        {
            SqlGate.Prior(this);
        }
        /// <summary>
        /// Устанавливает для полей fieldsName, признак видимости IsVisible
        /// </summary>
        /// <param name="fieldsName">Список полей, для которых устнавливается признак видимости</param>
        /// <param name="IsVisible">Признак видимости: true - поле видимое, false - поле не видимое</param>
        public void SetVisibleFields(List<string> fieldsName)
        {
            foreach (DataGridViewColumn n in DGV.Columns)
                n.Visible = false;

            for (int i = 0; i < fieldsName.Count; i++)
            {
                if (DGV.Columns[fieldsName[i].ToUpper()] != null)
                {
                    DGV.Columns[fieldsName[i]].Visible = true;
                    DGV.Columns[fieldsName[i]].DisplayIndex = i;
                }

            }
        }
        

		/// <summary>
        /// Результат выборки
        /// </summary>
        public DataTable DT { get { return this._dt; } }
        /// <summary>
        /// Первичный ключ для полученной выборки. Должен быть установлен до использования метода Open
        /// </summary>
        public List<string> PrimaryKey { get { return this._primaryKey; } }
        /// <summary>
        /// Связанный с секвенцией дата грид, если не равен null, то при открытии секвенция заполнит его значениями из запроса
        /// </summary>
        public DataGridView DGV { get { return this._dgv; } set { this._dgv = value; } }
        /// <summary>
        /// Список полей запроса
        /// </summary>
        public List<List<string>> Fields { get { return this._fields; } set { this._fields = value; } }

        public string Sql { get; set; }
        public SqlSwitch SqlSwitch { get { return this._sqlSwitch; } set { this._sqlSwitch = value; } }
        public int Index { get; set; }
        public int RecordCount { get; set; }
        public OrderBy OrderBy { get { return _orderBy; } set { _orderBy = value; } }
        public static ISqlGate SqlGate { get; set; }

        //Fields
        private List<VisibleColumn> _visibleColumn = new List<VisibleColumn>();
        private List<List<string>> _fields = new List<List<string>>();
        private SqlSwitch _sqlSwitch = new SqlSwitch();
        private DataTable _dt = new DataTable();
        private List<string> _primaryKey = new List<string>();
        private DataGridView _dgv;
        private OrderBy _orderBy = new OrderBy();
        
    }

    public struct OrderBy
    {
        public OrderBy(List<string> value, bool desc)
        {
            OrderByValue = value;
            Desc = desc;
        }

        public List<string> OrderByValue;
        public bool Desc;
    }

    public class SqlSwitch
    {
        /// <summary>
        /// Добавление условия в выборку
        /// </summary>
        /// <param name="name">Имя поля на которое накладывается условие</param>
        /// <param name="value">Значение</param>
        /// <param name="condition">Операция отношения</param>
        /// <param name="type">Тип условия</param>
        /// <param name="dir">Направление параметра</param>
        public void Add(string name, string value, SqlCondition condition, SqlType type, Direction dir)
        {
            SqlCase sqlCase = this._condition.Find(i => i.Name == name);
            if (sqlCase != null)
                this._condition.Remove(sqlCase);

            this._condition.Add(new SqlCase(name, value, condition, type, dir));

        }
        
        /// <summary>
        /// Очищаются текущие условия запроса. Очищается свойство Condition
        /// </summary>
        public void Clear()
        {
            this._condition.Clear();
        }
        public List<SqlCase> Condition 
        {
            get { return _condition; }
            set { this._condition = value; } 
        }

        private List<SqlCase> _condition = new List<SqlCase>();
    }

	[Serializable]
    public class SqlCase
    { 
        // Constructors
        public SqlCase(string name, string values, SqlCondition condition, SqlType type, Direction dir)
        {
            this._name = name;
            this._values = values;
            this._sqlCondition = condition;
            this._sqlType = type;
            this._dir = dir;
        }

        // Properties
        public string Name { get { return this._name; } }
        public string Values { get { return this._values; } }
        public SqlCondition SqlCondition { get { return this._sqlCondition; } }
        public SqlType SqlType { get { return this._sqlType; } }
        public Direction Dir { get { return this._dir; } }

        //Private
        private string _name;
        private string _values;
        private SqlCondition _sqlCondition;
        private SqlType _sqlType;
        private Direction _dir;
    }

	[Serializable]
    public enum SqlCondition { 
        equal,      /// равно
        not_eqaul,  /// не равно
        gt,         /// больше 
        lt,         /// меньше 
        gte,        /// больше или равно
        lte,        /// меньше или равно
        btw,        /// между
        like,       /// похоже
        in_enum,    /// вхождение в последовательность
        is_null,    /// Условие IS NULL
        not_null  /// Условие IS NOT NULL
    }

	[Serializable]
    public enum SqlType
    {
        sqlInt,     /// Условие типа integer
        sqlString,  /// Строковое условие
        sqlDate,    /// Условие типа дата
        sqlDouble  /// Условие на числа двойной точности
    }

	[Serializable]
    public enum Direction { input, output }

    [Serializable]
    public struct VisibleColumn
    {
        public string Name { get; set; }
        public bool IsVisible { get; set; }
    }

    public interface ISqlGate
    {
        void Open(Sequence sequence);
        void Next(Sequence sequence);
        void Prior(Sequence sequence);
    }



}
